package org.eliza.base.coroutinesx.flow

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeoutOrNull

private fun simple(): Flow<Int> = flow {
    for (i in 1..3) {
        delay(100)
        println("Emitting $i")
        emit(i)
    }
}

private fun withTimeoutOrNullx() = runBlocking<Unit> {
    println("===withTimeoutOrNullx===")
    withTimeoutOrNull(250) { // Timeout after 250ms
        simple().collect { value -> println(value) }
    }
    println("Done")
}

private suspend fun performRequest(request: Int): String {
    delay(200) // imitate long-running asynchronous work
    return "response $request"
}

private fun mapCollect() = runBlocking<Unit> {
    println("===mapCollect===")
    (1..3).asFlow() // a flow of requests
        .map { request -> performRequest(request) }
        .collect { response -> println(response) }
}

private fun emitTwo() = runBlocking<Unit> {
    println("===emitTwo===")

    var ii = 0
    (1..3).asFlow() // a flow of requests
        .transform { request ->
            emit("Making request $request")
            emit(performRequest(request))
        }
        .collect { response ->
            println("ii:$ii $response")
            ii++
        }
}

private fun numbers(): Flow<Int> = flow {
    try {
        emit(1)
        emit(2)
        println("This line will not execute")
        emit(3)
    } finally {
        println("Finally in numbers")
    }
}

private fun takeTwo() = runBlocking<Unit> {
    println("===takeTwo===")
    numbers()
        .take(2) // take only the first two
        .collect { value -> println(value) }
}

fun main() {


    withTimeoutOrNullx()
    mapCollect()
    emitTwo()
    takeTwo()


}
